﻿using System.Collections.Generic;
using System.Linq;

namespace Manoso.Data.FluentMap
{
    public interface IMapInsert<T> : IMapUpdate<T>
    {
    }

    internal class MapInsert<T> : MapUpdate<T>, IMapInsert<T>
    {
        protected override MapCommandType CommandType
        {
            get { return MapCommandType.Insert; }
        }

        public MapInsert()
        {
            IsMatch = NOT_MATCH;
        }

        public override void GetCommand(IMapTask task, IList<string> stack)
        {
            var sub = (T)task.Values[TableAlias];
            if (!IsMatch(sub)) return;

            if (ActionFix != null) ActionFix(sub);

            var insert = GenerateCommand(task.Adaptor, task, stack);

            if (string.IsNullOrEmpty(insert)) return;

            var returnCmd = MapReturns.Count <= 0 ? null : GenerateReturn(task.Adaptor, task);
            if (MapReturns.Count <= 0)
                task.AddCommand(insert, MapCommandType.Insert);
            else
            {
                if (task.Submit == null) return;

                LoadReturns(task);
                task.Submit(string.Join(string.Empty, stack) + insert + (returnCmd ?? string.Empty), () => ReadReturns(task));
            }
        }

        protected override string GenerateCommand(IMapAdaptor adaptor, IMapTask task, IList<string> stack)
        {
            var value = task.Values[TableAlias];
            LoadProperties(task, IncludeId);

            var properties = Columns.Select(x => x.Column);

            var insert = new List<string>();
            if (IsTable)
            {
                var id = GetDeclare(task, stack, true, MapReturns.Count > 0);
                insert.Add(adaptor.GetInsert(Target, properties));
                if (id != null && !IncludeId)
                {
                    var idParam = id.Column.Alias;
                    insert.Add(adaptor.GetIdentity(idParam));
                    if (MapReturns.Count > 0)
                        SetAssignment(task, stack, id, string.Empty);
                }
                
            }
            else
            {
                if (!IncludeId && MapReturns == null)
                {
                    var id = GetDeclare(task, stack, true);
                    if (id != null)
                    {
                        var idParam = id.Column.Alias;
                        insert.Add(adaptor.GetExecReturn(Target, idParam, properties));
                    }
                }
                else
                {
                    if (!ValueType.IsInstanceOfType(value))
                        insert.Add(adaptor.GetExec(Target, properties));
                }
            }
            return string.Join(string.Empty, insert);
        }

        protected override string GenerateReturn(IMapAdaptor adaptor, IMapTask task)
        {
            var sub = (T)task.Values[TableAlias];

            if (IsTable && IsMatch(sub) && MapReturns != null)
            {
                LoadIds(task);
                var ids = Keys;
                if (ids.Count() == 1 || CheckTstamp && ids.Count() == 2 && MapTstamp != null)
                {
                    var id = ids.First(x => x != MapTstamp);
                    var columns = MapReturns.Select(x => x.Column).ToArray();
                    return adaptor.GetReturn(Table, TableAlias, columns, new MapColumn(id.Column.Name, TableAlias));
                }
            }
            return null;
        }
    }
}